FEXP Solver  1.0.0.0
FEXPTopologieKDTree.h
Go to the documentation of this file.
1 // © FEXP, FEXPEnterprise Solver, Ing. Vaclav Rek
3 // KD-tree data structure for mapping of 3D topology (FE nodes).
4 // Compiler must support C++ ver.14 and later
6 #ifndef _CFEXPTOPOLOGIEKDTREE_H_
7 #define _CFEXPTOPOLOGIEKDTREE_H_
8 #include "FEXPCommon.h"
9 #include "FEXPDataContainer.h"
10 #include "FEXPGeom.h"
11 
17 
19 template<typename TValue>
21 {
22 public:
23  CFEXPKDHyperNode(size_t dimension);
24  CFEXPKDHyperNode(Ptr<TValue> & coordinates);
25  virtual ~CFEXPKDHyperNode() { }
26  // member data
28  // member functions
29  TValue GetDistance(const CFEXPKDHyperNode & nd1, const CFEXPKDHyperNode & nd2);
30  bool operator== (const CFEXPKDHyperNode & to_compare);
31 protected:
32  // [no protected members] -----------------------------
33 private:
34  // [no private members ] -----------------------------
35 };
36 
37 // member functions
39 //--------------------------------------------------------------------------------------
40 template<typename TValue>
42 //--------------------------------------------------------------------------------------
43 {
44 #if !COORD_OPTIMIZATION_IS_ON
45  _coordinates = CFEXPDataManager<TValue>::SafeAllocInstanceArray(dimension);
46  size_t idx;
47  FEXPCOMMON_FOREACH(FEXPCOMMON_DEFAULT_INDX, dimension - 1, idx)
48  _coordinates.get()[idx] = 0;
49 #endif
50 }
51 
52 //--------------------------------------------------------------------------------------
53 template<typename TValue>
55 //--------------------------------------------------------------------------------------
56 {
57 #if !COORD_OPTIMIZATION_IS_ON
58  auto length = coordinates.GetArrLength();
59  if (!_coordinates)
61  size_t idx;
63  _coordinates.get()[idx] = coordinates.get()[idx];
64 #else
65  _coordinates = coordinates;
66 #endif
67 }
68 
69 //--------------------------------------------------------------------------------------
70 template<typename TValue>
72 //--------------------------------------------------------------------------------------
73 {
74  size_t length1 = nd1._coordinates.GetArrLength();
75  size_t length2 = nd2._coordinates.GetArrLength();
76  if (length1 != length2)
77  FEXPCOMMON_EXCEPTION("Error: KD-tree: Wrong coordinate dimension!!!");
78 
79  size_t start = FEXPCOMMON_DEFAULT_INDX, end = length1 - 1;
80  size_t idx; TValue dist = 0;
81  FEXPCOMMON_FOREACH(start, end, idx)
82  dist += pow(nd2._coordinates.get()[idx] - nd1._coordinates.get()[idx], 2);
83  return sqrt(dist);
84 }
85 
86 //--------------------------------------------------------------------------------------
87 template<typename TValue>
89 //--------------------------------------------------------------------------------------
90 {
91  size_t length1 = _coordinates.GetArrLength();
92  size_t length2 = to_compare._coordinates.GetArrLength();
93  if (length1 != length2)
94  FEXPCOMMON_EXCEPTION("Error: KD-tree: Wrong coordinate dimension!!!");
95 
96  // compare values
97  size_t start = FEXPCOMMON_DEFAULT_INDX, end = length1 - 1;
98  size_t idx;
99  FEXPCOMMON_FOREACH(start, end, idx)
100  {
101  if (CFEXPBaseConvers::Compare<TValue>(
102  _coordinates.get()[idx], to_compare._coordinates.get()[idx]) == FEXPCOMMON_COMPARE_EQ)
103  continue;
104  return false;
105  }
106  return true;
107 }
108 
114 // primary template
115 template<typename TData, typename TValue, typename Enable = void>
116 class CFEXPKDTreeNode { };
119 template<typename TValue, typename TData>
121  // specialization
122  <TData, TValue, typename std::enable_if<std::is_base_of<ICFEXPFECoordinatesBase<TValue>, TData>::value>::type>
123 {
124 public:
126  : _data(data), _hpnd(hyp_node), _left(nullptr), _rght(nullptr) { }
127  virtual ~CFEXPKDTreeNode() { }
128 
129  // member data
134  std::vector<CFEXPKDTreeNode*> _same_nodes_data;
135 
136  // member function for inserting node to KD-tree
138  CFEXPKDTreeNode * node, Ptr<TData> & data, size_t level, size_t dim,
139  std::vector<Ptr<CFEXPKDTreeNode<TData, TValue>>> & collect_tree_nodes)
140  {
141  auto result = node;
142  if (!result)
143  {
144  auto new_tree_node = CFEXPDataManager<CFEXPKDTreeNode>::SafeAllocInstance(hyp_nd, data);
145  collect_tree_nodes.push_back(new_tree_node);
146  result = new_tree_node.get();
147  }
148  else if ((*hyp_nd) == (*node->_hpnd))
149  {
150  // add the same data as node to vector
151  auto new_tree_node = CFEXPDataManager<CFEXPKDTreeNode>::SafeAllocInstance(hyp_nd, data);
152  collect_tree_nodes.push_back(new_tree_node);
153  result->_same_nodes_data.push_back(new_tree_node.get());
154  return result;
155  }
156  else if (hyp_nd->_coordinates.get()[level] > node->_hpnd->_coordinates.get()[level])
157  result->_rght = InsertNode(hyp_nd, result->_rght, data, (level + 1) % dim, dim, collect_tree_nodes);
158  else
159  result->_left = InsertNode(hyp_nd, result->_left, data, (level + 1) % dim, dim, collect_tree_nodes);
160  return result;
161  }
162 
163  // member function for searching nodes which fitt bounding box
165  CFEXPKDTreeNode * node, size_t level, size_t dim, Ptr<std::vector<Ptr<TData>>> & result)
166  {
167  if (!node)
168  return;
169 
170  if (lower->_coordinates.get()[level] <= node->_hpnd->_coordinates.get()[level])
171  SearchRange(lower, upper, node->_left, (level + 1) % dim, dim, result);
172 
173  size_t idx;
175  {
176  auto to_continue = (idx < dim) &&
177  (lower->_coordinates.get()[idx] <= node->_hpnd->_coordinates.get()[idx]) &&
178  (upper->_coordinates.get()[idx] >= node->_hpnd->_coordinates.get()[idx]);
179  if (to_continue)
180  continue;
181  break;
182  }
183 
184  if (idx == dim)
185  {
186  // add node from tree
187  result->push_back(node->_data);
188  // add nodes with the same coordinates belong to tree node
189  FEXPCOMMON_FOREACH_ITER_FNC(node->_same_nodes_data, { result->push_back(IT->_data); });
190  }
191 
192  if (upper->_coordinates.get()[level] > node->_hpnd->_coordinates.get()[level])
193  SearchRange(lower, upper, node->_rght, (level + 1) % dim, dim, result);
194  }
195 protected:
196  // [no protected members] -----------------------------
197 private:
198  // [no private members ] -----------------------------
199 };
200 
206 
208 template<typename TData, typename TValue>
210 {
211 public:
212  CFEXPTopologieKDTree(size_t dimension);
213  virtual ~CFEXPTopologieKDTree() { }
214 
215  void CreateTopologyTree(Ptr<ICFEXPDataModelContIntf> container, size_t opt_id);
217  CreateTopologyTreeProgress(Ptr<ICFEXPDataModelContIntf> container, size_t dimension, size_t opt_id, std::string text);
218 
219  // member function for searching nodes which fitt bounding box
221  GetNodesFromBoundingBox(const std::vector<TValue> & min_bound, const std::vector<TValue> & max_bound);
222  // insert new data to tree
223  void InsertData(Ptr<TData> & data);
224  void InsertData(std::vector<Ptr<TData>> & data);
225 protected:
226  // [no protected members] -----------------------------
227 private:
228  size_t _tree_dimension;
229  size_t _tree_node_count;
231 
232  // KD-tree nodes (store here to deallocate)
233  std::vector<Ptr<CFEXPKDTreeNode<TData, TValue>>> _kd_tree_nodes;
234  // KD-tree hyper nodes (store here to deallocate)
235  std::vector<Ptr<CFEXPKDHyperNode<TValue>>> _kd_tree_hyper_nodes;
236 };
237 
238 // kd tree default data structure typedef
239 template<typename TData>
241 
242 // member functions
244 //--------------------------------------------------------------------------------------
245 template<typename TData, typename TValue>
247  : _tree_dimension(dimension), _tree_node_count(FEXPCOMMON_DEFAULT_VALUE), _root(nullptr) { }
248 //--------------------------------------------------------------------------------------
249 
250 //--------------------------------------------------------------------------------------
251 template<typename TData, typename TValue>
254 //--------------------------------------------------------------------------------------
255 {
256  container->IterateModElems([this](auto item)
257  {
258  InsertData(FEXPCOMMON_DYNCAST(ICFEXPModelDataIntf, TData, item));
259  return true;
260  }, opt_id);
261 }
262 
263 //--------------------------------------------------------------------------------------
264 template<typename TData, typename TValue>
266  ::CreateTopologyTreeProgress(Ptr<ICFEXPDataModelContIntf> container, size_t dimension, size_t opt_id, std::string text)
267 //--------------------------------------------------------------------------------------
268 {
270  CFEXPAsyncRunner::RunProcedureWithProgress([&]
271  {
273  result->CreateTopologyTree(container, opt_id);
274  }, text);
275  return result;
276 }
277 
278 //--------------------------------------------------------------------------------------
279 template<typename TData, typename TValue>
281 //--------------------------------------------------------------------------------------
282 {
283  if (!data)
284  FEXPCOMMON_EXCEPTION("Error: KD-tree: Try add null data to tree!!!");
285  auto array = data->GetCoordArray();
286 
287  if (array.GetArrLength() != _tree_dimension)
288  FEXPCOMMON_EXCEPTION("Error: KD-tree: Try add data to tree with wrong coordinate dimension!!!");
289 
290  auto hyper_node = CFEXPDataManager<CFEXPKDHyperNode<TValue>>::SafeAllocInstance(array);
291  _kd_tree_hyper_nodes.push_back(hyper_node);
292  // insert node
293  _root = CFEXPKDTreeNode<TData, TValue>::InsertNode(hyper_node.get(), _root,
294  data, FEXPCOMMON_DEFAULT_VALUE, _tree_dimension, _kd_tree_nodes);
295 }
296 
297 //--------------------------------------------------------------------------------------
298 template<typename TData, typename TValue>
300 //--------------------------------------------------------------------------------------
301 {
302  FEXPCOMMON_FOREACH_ITER_FNC(data, { InsertData(IT); });
303 }
304 
305 //--------------------------------------------------------------------------------------
306 template<typename TData, typename TValue>
308  ::GetNodesFromBoundingBox(const std::vector<TValue> & min_bound, const std::vector<TValue> & max_bound)
309 //--------------------------------------------------------------------------------------
310 {
311  size_t length1 = min_bound.size();
312  size_t length2 = max_bound.size();
313  if ((length1 != length2) || (length1 != _tree_dimension))
314  FEXPCOMMON_EXCEPTION("Error: KD-tree: Wrong coordinate dimension!!!");
315 
316  auto minb = CFEXPDataManager<TValue>::SafeAllocInstanceArray(_tree_dimension);
317  std::copy(min_bound.begin(), min_bound.end(), minb.get());
318  auto mind = CFEXPDataManager<CFEXPKDHyperNode<TValue>>::SafeAllocInstance(minb);
319 
320  auto maxb = CFEXPDataManager<TValue>::SafeAllocInstanceArray(_tree_dimension);
321  std::copy(max_bound.begin(), max_bound.end(), maxb.get());
322  auto maxd = CFEXPDataManager<CFEXPKDHyperNode<TValue>>::SafeAllocInstance(maxb);
323 
324  // find nodes in bounding box range
325  auto result = CFEXPDataManager<std::vector<Ptr<TData>>>::SafeAllocInstance();
326  CFEXPKDTreeNode<TData, TValue>::SearchRange(mind.get(), maxd.get(), _root, FEXPCOMMON_DEFAULT_VALUE, _tree_dimension, result);
327  return result;
328 }
329 
330 #endif // !_CFEXPTOPOLOGIEKDTREE_H_
It represents a general node of a normed k-dimensional real space.
Definition: FEXPTopologieKDTree.h:20
#define IT
Definition: FEXPCommon.h:155
It contains algorithm for building of a kd-tree data structure and it also process range queries...
Definition: FEXPTopologieKDTree.h:209
CFEXPKDTreeNode(CFEXPKDHyperNode< TValue > *hyp_node, Ptr< TData > &data)
Definition: FEXPTopologieKDTree.h:125
CFEXPTopologieKDTree(size_t dimension)
Definition: FEXPTopologieKDTree.h:246
#define FEXPCOMMON_FOREACH(start, end, index)
Definition: FEXPCommon.h:153
#define FEXPCOMMON_FOREACH_ITER_FNC(data, lambda_body)
Definition: FEXPCommon.h:157
Definition: FEXPCommon.h:276
CFEXPKDHyperNode(size_t dimension)
Definition: FEXPTopologieKDTree.h:41
#define FEXPCOMMON_DEFAULT_INDX
Definition: FEXPCommon.h:171
#define FEXPCOMMON_EXCEPTION(error_text)
Definition: FEXPCommon.h:143
#define FEXPCOMMON_COMPARE_EQ
Definition: FEXPCommon.h:1093
void CreateTopologyTree(Ptr< ICFEXPDataModelContIntf > container, size_t opt_id)
Definition: FEXPTopologieKDTree.h:253
static CFEXPKDTreeNode * InsertNode(CFEXPKDHyperNode< TValue > *hyp_nd, CFEXPKDTreeNode *node, Ptr< TData > &data, size_t level, size_t dim, std::vector< Ptr< CFEXPKDTreeNode< TData, TValue >>> &collect_tree_nodes)
Definition: FEXPTopologieKDTree.h:137
static Ptr< TType > SafeAllocInstance(VarArgs &&... inpar)
It allocates data.
Definition: FEXPCommon.h:392
virtual ~CFEXPTopologieKDTree()
Definition: FEXPTopologieKDTree.h:213
static Ptr< CFEXPTopologieKDTree< TData, TValue > > CreateTopologyTreeProgress(Ptr< ICFEXPDataModelContIntf > container, size_t dimension, size_t opt_id, std::string text)
Definition: FEXPTopologieKDTree.h:266
Base interface for system element.
Definition: FEXPDataContainer.h:28
bool operator==(const CFEXPKDHyperNode &to_compare)
Definition: FEXPTopologieKDTree.h:88
#define FEXPCOMMON_DEFAULT_VALUE
Definition: FEXPCommon.h:179
virtual ~CFEXPKDHyperNode()
Definition: FEXPTopologieKDTree.h:25
Definition: FEXPTopologieKDTree.h:116
Ptr< TValue > _coordinates
Definition: FEXPTopologieKDTree.h:27
Ptr< std::vector< Ptr< TData > > > GetNodesFromBoundingBox(const std::vector< TValue > &min_bound, const std::vector< TValue > &max_bound)
Definition: FEXPTopologieKDTree.h:308
static Ptr< TType > SafeAllocInstanceArray(size_t length)
It allocates data array.
Definition: FEXPCommon.h:410
Smart pointer.
Definition: FEXPCommon.h:274
size_t GetArrLength() const
Definition: FEXPCommon.h:296
#define FEXPCOMMON_DYNCAST(clsfrom, clsto, variable)
Definition: FEXPCommon.h:138
void InsertData(Ptr< TData > &data)
Definition: FEXPTopologieKDTree.h:280
TValue GetDistance(const CFEXPKDHyperNode &nd1, const CFEXPKDHyperNode &nd2)
Definition: FEXPTopologieKDTree.h:71
static void SearchRange(CFEXPKDHyperNode< TValue > *lower, CFEXPKDHyperNode< TValue > *upper, CFEXPKDTreeNode *node, size_t level, size_t dim, Ptr< std::vector< Ptr< TData >>> &result)
Definition: FEXPTopologieKDTree.h:164